package com.ruoyi.common.utils.encryption;

import com.ruoyi.common.utils.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;

/**
 * AES加密工具
 *
 * @author KevenPotter
 * @date 2024-04-26 13:59:20
 */
public class AesUtils {

    public static final String ENCRYPTION_ALGORITHM = "AES";
    public static final String CIPHER_PARAM = "AES/CBC/PKCS5Padding";
    public static final String CIPHER_PARAM_FOR_MYSQL = "AES/ECB/PKCS5Padding";
    public static final Charset UTF_8 = StandardCharsets.UTF_8;

    /*令牌*/
    private static final String KEY = "weiyuan@BeiJing@2008@zhxt@";
    /*MySQL令牌*/
    private static final String KEY_FOR_MYSQL = "weiyuan@Beijing@";
    /*偏移量*/
    private static final String OFFSET = "0102030405060708";

    /*AES初始化判断*/
    public static boolean initialized = false;


    /**
     * AES加密
     *
     * @param content 加密内容
     * @return String
     * @author KevenPotter
     * @date 2024-04-26 14:20:11
     */
    public static String encrypt(String content) {
        try {
            Cipher ciper = Cipher.getInstance(CIPHER_PARAM);
            byte[] key = new byte[32];
            for (int i = 0; i < 32; i++) {
                if (i < KEY.getBytes().length) {
                    key[i] = KEY.getBytes()[i];
                } else {
                    key[i] = 0;
                }
            }
            SecretKeySpec key_ = new SecretKeySpec(key, ENCRYPTION_ALGORITHM);
            IvParameterSpec iv = new IvParameterSpec(OFFSET.getBytes());
            ciper.init(Cipher.ENCRYPT_MODE, key_, iv);
            byte[] encode = Base64.getEncoder().encode(ciper.doFinal(content.getBytes()));
            return Base64.getEncoder().encodeToString(encode);
        } catch (InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException | NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * AES加密(未偏移)
     *
     * @param content 加密内容
     * @return String
     * @author KevenPotter
     * @date 2024-04-26 14:20:48
     */
    public static String encryptForMySQL(String content) {
        if (StringUtils.isEmpty(content)) return null;
        try {
            byte[] raw = KEY_FOR_MYSQL.getBytes(UTF_8);
            SecretKeySpec key_ = new SecretKeySpec(raw, ENCRYPTION_ALGORITHM);
            Cipher cipher = Cipher.getInstance(CIPHER_PARAM_FOR_MYSQL);
            cipher.init(Cipher.ENCRYPT_MODE, key_);
            byte[] encrypted = cipher.doFinal(content.getBytes(UTF_8));
            return new BASE64Encoder().encode(encrypted);
        } catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException | NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * AES解密
     *
     * @param content 解密内容
     * @return 解密后的内容
     * @author KevenPotter
     * @date 2024-04-26 14:21:33
     */
    public static String decrypt(String content) {
        try {
            Cipher ciper = Cipher.getInstance(CIPHER_PARAM);
            byte[] key = new byte[32];
            for (int i = 0; i < 32; i++) {
                if (i < KEY.getBytes().length) {
                    key[i] = KEY.getBytes()[i];
                } else {
                    key[i] = 0;
                }
            }
            SecretKeySpec key_ = new SecretKeySpec(key, ENCRYPTION_ALGORITHM);
            IvParameterSpec iv = new IvParameterSpec(OFFSET.getBytes());
            ciper.init(Cipher.DECRYPT_MODE, key_, iv);
            byte[] text = ciper.doFinal(Base64.getDecoder().decode(Base64.getDecoder().decode(content)));
            return new String(text);
        } catch (InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException | NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * AES解密(未偏移)
     *
     * @param content 解密内容
     * @return 解密后的内容
     * @author KevenPotter
     * @date 2024-04-26 14:21:49
     */
    public static String decryptForMySQL(String content) {
        if (StringUtils.isEmpty(content)) return null;
        try {
            byte[] raw = KEY_FOR_MYSQL.getBytes(UTF_8);
            SecretKeySpec key_ = new SecretKeySpec(raw, ENCRYPTION_ALGORITHM);
            Cipher cipher = Cipher.getInstance(CIPHER_PARAM_FOR_MYSQL);
            cipher.init(Cipher.DECRYPT_MODE, key_);
            byte[] encrypted1 = new BASE64Decoder().decodeBuffer(content);
            try {
                byte[] original = cipher.doFinal(encrypted1);
                return new String(original, UTF_8);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }

    public static void main(String[] args) throws Exception {
        String content = "测试中文：一二三四 测试英文：kevenPotter 测试数字：123456";
        System.out.println("加密前：" + content);
        content = encryptForMySQL(content);
        System.out.println("加密后：" + content);
        content = decryptForMySQL(content);
        System.out.println("解密后：" + content);
    }

    /**
     * AES解密
     *
     * @param content 密文
     * @param keyByte 令牌值
     * @param ivByte  偏移量
     * @return 返回解密后的字节数组
     * @author KevenPotter
     * @date 2024-04-26 14:22:03
     */
    public static byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws InvalidAlgorithmParameterException {
        initialize();
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            Key sKeySpec = new SecretKeySpec(keyByte, "AES");
            cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化
            return cipher.doFinal(content);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 判断初始化参数
     *
     * @author KevenPotter
     * @date 2024-04-26 14:22:12
     */
    public static void initialize() {
        if (initialized) return;
        Security.addProvider(new BouncyCastleProvider());
        initialized = true;
    }

    // 生成iv

    /**
     * 生成偏移量(iv)
     *
     * @param iv 字节数组形式的偏移量
     * @return 返回加密参数
     * @author KevenPotter
     * @date 2024-04-26 14:22:55
     */
    public static AlgorithmParameters generateIV(byte[] iv) throws Exception {
        AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
        params.init(new IvParameterSpec(iv));
        return params;
    }

}
